#include "bindings/bindings_rive_event.h"
#include "helpers/exception_handler.h"
#include "helpers/general.h"
#include "rive/custom_property_boolean.hpp"
#include "rive/custom_property_number.hpp"
#include "rive/custom_property_string.hpp"
#include "rive/open_url_event.hpp"

namespace ohos_rive {
const char *GetTargetValue(rive::OpenUrlEvent *urlEvent)
{
    switch (urlEvent->targetValue()) {
        case 0:
            return "_blank";
        case 1:
            return "_parent";
        case 2:
            return "_self";
        case 3:
            return "_top";
    }
    return "_blank";
}

// TODO GetProperties
napi_value GetProperties(napi_env env, rive::Event *event)
{
    napi_value propertiesObject;
    napi_status status = napi_create_object(env, &propertiesObject);
    if (status != napi_ok || propertiesObject == nullptr) {
        NapiExceptionHandler::CheckAndRethrow(env);
        return nullptr;
    }

    if (event == nullptr) {
        return propertiesObject;
    }

    for (auto child : event->children()) {
        if (child->is<rive::CustomProperty>()) {
            if (!child->name().empty()) {
                napi_value key = NapiExceptionHandler::CreateString(env, child->name().c_str());
                if (key == nullptr)
                    continue;

                switch (child->coreType()) {
                    case rive::CustomPropertyBoolean::typeKey: {
                        bool propertyValue = child->as<rive::CustomPropertyBoolean>()->propertyValue();
                        napi_value value;
                        status = napi_get_boolean(env, propertyValue, &value);
                        if (status == napi_ok) {
                            NapiExceptionHandler::SetProperty(env, propertiesObject, child->name().c_str(), value);
                        }
                        break;
                    }
                    case rive::CustomPropertyString::typeKey: {
                        std::string propertyValue = child->as<rive::CustomPropertyString>()->propertyValue();
                        napi_value value = NapiExceptionHandler::CreateString(env, propertyValue.c_str());
                        if (value != nullptr) {
                            NapiExceptionHandler::SetProperty(env, propertiesObject, child->name().c_str(), value);
                        }
                        break;
                    }
                    case rive::CustomPropertyNumber::typeKey: {
                        float propertyValue = child->as<rive::CustomPropertyNumber>()->propertyValue();
                        napi_value value;
                        status = napi_create_double(env, propertyValue, &value);
                        if (status == napi_ok) {
                            NapiExceptionHandler::SetProperty(env, propertiesObject, child->name().c_str(), value);
                        }
                        break;
                    }
                }
            }
        }
    }

    return propertiesObject;
}

napi_value RiveOpenURLEventURL(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);
    if (event->is<rive::OpenUrlEvent>()) {
        auto urlEvent = event->as<rive::OpenUrlEvent>();
        napi_value result;
        napi_create_string_utf8(env, urlEvent->url().c_str(), NAPI_AUTO_LENGTH, &result);
        return result;
    }

    napi_value result;
    napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
    return result;
}

napi_value RiveOpenURLEventTarget(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);
    if (event->is<rive::OpenUrlEvent>()) {
        auto urlEvent = event->as<rive::OpenUrlEvent>();
        const char *target = GetTargetValue(urlEvent);

        napi_value result;
        napi_create_string_utf8(env, target, NAPI_AUTO_LENGTH, &result);
        return result;
    }

    napi_value result;
    napi_create_string_utf8(env, "_blank", NAPI_AUTO_LENGTH, &result);
    return result;
}

napi_value RiveEventName(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);
    if (event == nullptr) {
        LOGE("Event pointer is null");
        napi_value result;
        napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
        return result;
    }
    napi_value result;
    napi_create_string_utf8(env, event->name().c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}

napi_value RiveEventType(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);
    napi_value result;
    napi_create_int32(env, static_cast<int32_t>(event->coreType()), &result);
    return result;
}

napi_value RiveEventProperties(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);
    return GetProperties(env, event);
}

// TODO Java_app_rive_runtime_kotlin_core_RiveEvent_cppData
napi_value RiveEventData(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_value thisArg;
    void *data;

    napi_get_cb_info(env, info, &argc, args, &thisArg, &data);

    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ref;
    napi_get_value_int64(env, args[0], &ref);

    auto *event = reinterpret_cast<rive::Event *>(ref);

    napi_value eventObject;
    napi_create_object(env, &eventObject);

    if (event == nullptr) {
        return eventObject;
    }

    // 设置名称
    napi_value nameKey;
    napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &nameKey);
    napi_value nameValue;
    napi_create_string_utf8(env, event->name().c_str(), NAPI_AUTO_LENGTH, &nameValue);
    napi_set_property(env, eventObject, nameKey, nameValue);

    if (event->is<rive::OpenUrlEvent>()) {
        auto urlEvent = event->as<rive::OpenUrlEvent>();

        // 设置类型
        napi_value typeKey;
        napi_create_string_utf8(env, "type", NAPI_AUTO_LENGTH, &typeKey);
        napi_value typeValue;
        napi_create_int32(env, event->coreType(), &typeValue);
        napi_set_property(env, eventObject, typeKey, typeValue);

        // 设置URL
        napi_value urlKey;
        napi_create_string_utf8(env, "url", NAPI_AUTO_LENGTH, &urlKey);
        napi_value urlValue;
        napi_create_string_utf8(env, urlEvent->url().c_str(), NAPI_AUTO_LENGTH, &urlValue);
        napi_set_property(env, eventObject, urlKey, urlValue);

        // 设置目标
        napi_value targetKey;
        napi_create_string_utf8(env, "target", NAPI_AUTO_LENGTH, &targetKey);
        napi_value targetValue;
        const char *target = GetTargetValue(urlEvent);
        napi_create_string_utf8(env, target, NAPI_AUTO_LENGTH, &targetValue);
        napi_set_property(env, eventObject, targetKey, targetValue);
    }

    // 设置属性
    napi_value propertiesKey;
    napi_create_string_utf8(env, "properties", NAPI_AUTO_LENGTH, &propertiesKey);
    napi_value propertiesValue = GetProperties(env, event);
    napi_set_property(env, eventObject, propertiesKey, propertiesValue);

    return eventObject;
}

} // namespace ohos_rive
